﻿using System;
using System.Security.Permissions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.Workflow;

namespace Masood.SharePoint.ApprovalWorkflowFix.WorkflowCompletedReceiver
{
    /// <summary>
    /// List Workflow Events
    /// </summary>
    public class WorkflowCompletedReceiver : SPWorkflowEventReceiver
    {
        /// <summary>
        /// A workflow was completed.
        /// </summary>
        public override void WorkflowCompleted(SPWorkflowEventProperties properties)
        {
            base.WorkflowCompleted(properties);
            PublishItemBasedOnWorkflowStatus(properties);
        }

        private void PublishItemBasedOnWorkflowStatus(SPWorkflowEventProperties properties)
        {
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                using (SPSite site = new SPSite(properties.WebUrl))
                {
                    using (SPWeb web = site.OpenWeb(properties.RelativeWebUrl))
                    {
                        //IConfigReader configReader = (IConfigReader)new ConfigReader(site.Url);

                        SPListItem workflowHistoryItem = GetWorkflowHistoryItem(web, properties);
                        if (workflowHistoryItem == null)
                            return;

                        SPListItem item = GetItemForThisWorkflow(web, workflowHistoryItem, properties);

                        //Provide association name so that it can ONLY approve item of that workflow
                        string associationName = "Approval workflow"; //configReader.GetWorkflowAssociationName();

                        //if (configReader.ValueInConfig("ControlledContentTypeName", Helper.GetParentContentType(item)) &&
                        //        !configReader.ValueInConfig("ExclusionLibraryURL", Helper.GetLibraryUrl(item.ParentList)))                        
                        //{
                            //This code runs for each workflow available in the site
                            //so just make sure you are not intrupting other workflow (for instance your custom one, collect feedback etc)
                            //and make sure it approve or reject for your specific libraries
                            MarkItemApproveOrRejectBasedWorkflowStatus(item, web, associationName, properties);
                        //}
                    }
                }
            });
        }

        private void MarkItemApproveOrRejectBasedWorkflowStatus(SPListItem item, SPWeb web, string associationName, SPWorkflowEventProperties properties)
        {
            string status = GetStatusOfRuningWorkflow(item, associationName);

            //we are only interested in OUR WORKFLOW ASSOCIATION (i.e. configured in Settings List)
            //if it is different, then it returns empty string
            if (string.IsNullOrEmpty(status))
                return;

            item.ModerationInformation.Status = SPModerationStatusType.Denied;
            if (status.Equals("Approved"))
                item.ModerationInformation.Status = SPModerationStatusType.Approved;

            item.Update();
        }

        private string GetStatusOfRuningWorkflow(SPListItem item, string workflowAssociationName)
        {
            string workflowStatus = string.Empty;
            foreach (SPField field in item.Fields)
            {
                if (field is SPFieldWorkflowStatus)
                {
                    SPFieldWorkflowStatus statusField = (SPFieldWorkflowStatus)field;
                    if (statusField.Title == workflowAssociationName)
                    {
                        int statusValue = int.Parse(item[statusField.StaticName].ToString());
                        workflowStatus = statusField.GetFieldValueAsHtml(statusValue);
                        break;
                    }
                }
            }

            return workflowStatus;
        }

        private SPListItem GetItemForThisWorkflow(SPWeb web, SPListItem workflowHistoryItem, SPWorkflowEventProperties properties)
        {
            int itemId = Convert.ToInt32(workflowHistoryItem["ows_Item"].ToString());
            Guid itemListGuid = new Guid(workflowHistoryItem["ows_List"].ToString());

            SPList itemParentList = web.Lists[itemListGuid];
            SPListItem item = itemParentList.GetItemById(itemId);

            return item;
        }

        private SPListItem GetWorkflowHistoryItem(SPWeb web, SPWorkflowEventProperties properties)
        {
            string caml = string.Format(@"<Where>
                                              <And>
                                                 <Eq>
                                                    <FieldRef Name='WorkflowInstance' />
                                                    <Value Type='Text'>{0}</Value>
                                                 </Eq>
                                                 <Eq>
                                                    <FieldRef Name='Event' />
                                                    <Value Type='WorkflowEventType'>2</Value>
                                                 </Eq>
                                              </And>
                                           </Where>", properties.InstanceId.ToString("B"));

            SPList workflowHistory = web.Lists["Workflow History"];
            SPQuery query = new SPQuery();
            query.Query = caml;
            SPListItemCollection items = workflowHistory.GetItems(query);

            if (items.Count >= 1)
            {
                return items[0];
            }

            return null;
        } 
    }
}